import { Location } from '@angular/common';
import { Component, ComponentRef, OnDestroy, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { ExceptionHandler } from 'src/app/handler/exception.handler';
import { DataRegister, NodePath, Page, Template, Workflow, WorkflowNodeItem, WorkflowOrderNodesItem } from 'src/app/models';
import { WorkflowService } from 'src/app/services';
import { PageTitleService } from 'src/app/services/page-title.service';
import { PageLayoutCommonComponent } from '../page-layouts/page-layout-common.component';
import { WorkflowPageService } from './workflow-page.service';

@Component({
  selector: 'zepride-workflow-page-container',
  templateUrl: './workflow-page-container.component.html',
  styleUrls: ['./workflow-page-container.component.less']
})
export class WorkflowPageContainerComponent implements OnInit, OnDestroy {

  workflowId = '';
  workflow: Workflow = {} as Workflow;
  rendering = false;
  templates: Template[];
  @ViewChild('containerRef', { read: ViewContainerRef }) containerRef: ViewContainerRef;
  layoutComponentRef: ComponentRef<PageLayoutCommonComponent>;
  pageId = '';
  page: Page;
  workflowUpdate$: Subscription;
  nodeValidChanged$: Subscription;

  constructor(
    private activatedRoute: ActivatedRoute,
    private workflowService: WorkflowService,
    public workflowPageService: WorkflowPageService,
    private router: Router,
    private phSvr: PageTitleService,
    private location: Location
  ) { }

  ngOnInit(): void {
    this.activatedRoute.paramMap.subscribe(async paramMap => {
      try {
        this.workflowId = paramMap.get('workflowId');
        this.workflow = await this.getWorkflowById(this.workflowId);
        this.workflowService.currentWorkflow = this.workflow;
        let flowNodeId = this.activatedRoute.firstChild && this.activatedRoute.firstChild.snapshot.paramMap.get('flowNodeId');
        // this.setPageHeader(this.workflow);
        if (!flowNodeId) {
          const node = this.getStartNode(this.workflow.workflowNodeItems, this.workflow.paths);
          flowNodeId = node.flowNodeId;
        }
        this.navToNodePage(flowNodeId);
      } catch (error) {
        ExceptionHandler.current.handleError(error);
      }
    });
    this.registerWorkflowUpdate();
    this.registerNodesValidChanged();
  }


  getWorkflowById(workflowId: string) {
    return this.workflowService.getWorkflowById(workflowId);
  }

  navToNodePage(flowNodeId: string) {
    const queryParams = this.activatedRoute.snapshot.queryParams;
    this.router.navigate([`home/page/workflow-page/${this.workflowId}/${flowNodeId}`], {
      queryParams
    });
    this.setCurrentNodeId(flowNodeId);
  }

  onNodeSelected(nodeItem: WorkflowNodeItem) {
    this.navToNodePage(nodeItem.flowNodeId);
  }

  getStartNode(workflowNodeItems: WorkflowOrderNodesItem[], paths: NodePath[]) {
    const endIds = paths.map(path => path.endNodeId);
    const endIdsSet = new Set(endIds);
    const startItem = workflowNodeItems.find(item => {
      const index = Array.from(endIdsSet).findIndex(id => id === item.flowNodeId);
      return index === -1;
    });
    return startItem;
  }

  getCurrentNode(workflowNodeItems: WorkflowOrderNodesItem[], paths: NodePath[]) {
    const item = workflowNodeItems.find(i => i.status === 'process');
    if (item) {
      return item;
    } else {
      return this.getStartNode(workflowNodeItems, paths);
    }
  }

  setCurrentNodeId(nodeItemId: string) {
    if (!nodeItemId) {
      return;
    }
    this.workflowPageService.currentNodeId = nodeItemId;
  }

  registerWorkflowUpdate() {
    this.workflowUpdate$ = this.workflowPageService.workflowUpdated.subscribe(dataRegister => {
      if (!dataRegister) {
        return;
      }
      this.workflow.workflowNodeItems = this.workflowService.updateNodeByDataRegister(dataRegister, this.workflow);
    });
  }

  registerNodesValidChanged() {
    this.nodeValidChanged$ = this.workflowPageService.nodeValidChanged.subscribe(data => {
      this.workflow.workflowNodeItems.forEach(node => {
        const target = data.find(item => item.id === node.flowNodeId);
        node.disabled = target ? target.disabled : false;
      });
    });
  }

  back() {
    this.location.back();
  }

  ngOnDestroy() {
    if (this.workflowUpdate$) {
      this.workflowUpdate$.unsubscribe();
    }

    // this.workflowService.setCurrentWorkflow(null);
  }
}
